{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n============================\nUnderfitting vs. Overfitting\n============================\n\nThis example demonstrates the problems of underfitting and overfitting and\nhow we can use linear regression with polynomial features to approximate\nnonlinear functions. The plot shows the function that we want to approximate,\nwhich is a part of the cosine function. In addition, the samples from the\nreal function and the approximations of different models are displayed. The\nmodels have polynomial features of different degrees. We can see that a\nlinear function (polynomial with degree 1) is not sufficient to fit the\ntraining samples. This is called **underfitting**. A polynomial of degree 4\napproximates the true function almost perfectly. However, for higher degrees\nthe model will **overfit** the training data, i.e. it learns the noise of the\ntraining data.\nWe evaluate quantitatively **overfitting** / **underfitting** by using\ncross-validation. We calculate the mean squared error (MSE) on the validation\nset, the higher, the less likely the model generalizes correctly from the\ntraining data.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "print(__doc__)\n\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.preprocessing import PolynomialFeatures\nfrom sklearn.linear_model import LinearRegression\nfrom sklearn.model_selection import cross_val_score\n\n\ndef true_fun(X):\n    return np.cos(1.5 * np.pi * X)\n\nnp.random.seed(0)\n\nn_samples = 30\ndegrees = [1, 4, 15]\n\nX = np.sort(np.random.rand(n_samples))\ny = true_fun(X) + np.random.randn(n_samples) * 0.1\n\nplt.figure(figsize=(14, 5))\nfor i in range(len(degrees)):\n    ax = plt.subplot(1, len(degrees), i + 1)\n    plt.setp(ax, xticks=(), yticks=())\n\n    polynomial_features = PolynomialFeatures(degree=degrees[i],\n                                             include_bias=False)\n    linear_regression = LinearRegression()\n    pipeline = Pipeline([(\"polynomial_features\", polynomial_features),\n                         (\"linear_regression\", linear_regression)])\n    pipeline.fit(X[:, np.newaxis], y)\n\n    # Evaluate the models using crossvalidation\n    scores = cross_val_score(pipeline, X[:, np.newaxis], y,\n                             scoring=\"neg_mean_squared_error\", cv=10)\n\n    X_test = np.linspace(0, 1, 100)\n    plt.plot(X_test, pipeline.predict(X_test[:, np.newaxis]), label=\"Model\")\n    plt.plot(X_test, true_fun(X_test), label=\"True function\")\n    plt.scatter(X, y, edgecolor='b', s=20, label=\"Samples\")\n    plt.xlabel(\"x\")\n    plt.ylabel(\"y\")\n    plt.xlim((0, 1))\n    plt.ylim((-2, 2))\n    plt.legend(loc=\"best\")\n    plt.title(\"Degree {}\\nMSE = {:.2e}(+/- {:.2e})\".format(\n        degrees[i], -scores.mean(), scores.std()))\nplt.show()"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.6.9"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}